#include "testing_framework.h"
#include <iostream>
#include <iomanip>
#include <fstream>
#include <random>
#include <chrono>
#include "windows.h"
#include "psapi.h"

using namespace std;
using namespace std::chrono;

TestResults TestManager::TestThis(void* testobj, void(*testfunc)(void*, unsigned int), unsigned int numiterations, char* outputfile, long long int seed) {
	unsigned int *test_inputs = new unsigned int[numiterations];
	ofstream resultsfile;
	steady_clock::time_point start, end;
	PROCESS_MEMORY_COUNTERS pmc;
	long long int overhead;
	TestResults results;
	
	//Initialize the input set	
	for(unsigned int i = 0; i < numiterations; ++i)
		test_inputs[i] = i;

	if ( seed < 0 ) seed = (unsigned long)system_clock::now().time_since_epoch().count();
	default_random_engine generator;
	generator.seed((unsigned int)seed);

	uniform_real_distribution<double> distribution(0.0,1.0);

	//Make random swaps to create a random sequence of the inputs
	for(unsigned int i = numiterations; i > 0; --i){
		unsigned int v = (unsigned int)(distribution(generator) * i);
		unsigned int o = test_inputs[v];
		test_inputs[v] = test_inputs[i-1];
		test_inputs[i-1] = o;
	}

	GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
	overhead = pmc.WorkingSetSize;

	start = steady_clock::now();

	for (unsigned int i = 0; i < numiterations; ++i) {	
		testfunc(testobj, test_inputs[i]);
	}

	end = steady_clock::now();
	results.elapsedTime = (duration_cast<duration<double>>(end - start)).count();

	GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
	results.ramUsed = (long long int)pmc.WorkingSetSize - overhead;

	resultsfile.open(outputfile, ios::out | ios::app);
	if (resultsfile.is_open())
		resultsfile << setw(15) << results.ramUsed << " - " << left << setw(10) << results.elapsedTime << " : " << seed << endl;

	return results;
}